<?php

namespace App\Model;

use App\Interface\Pay\AliPaymentStrategy;
use App\Services\AdapayService;
use App\Services\BankService;
use App\Services\Bolai\PackService;
use App\Services\Iot\IotService1 as IotService;
use App\Services\PaymentStrategyFactory;
use Hyperf\Database\Model\Relations\BelongsTo;
use Hyperf\Database\Model\Relations\HasOne;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Utils\Arr;
use Hyperf\Redis\Redis;
use Carbon\Carbon;
use Util\Common;


class Order extends Model
{

    public bool $timestamps = true;
    protected ?string $table = 'orders';

    protected array $casts = [
        'start_at' => 'datetime',
        'stop_at' => 'datetime'
    ];
    protected array $guarded =[

    ];

    const STATUS_UNPAID = 0;
    const STATUS_PAID = 1;
    const STATUS_USING = 2;
    const STATUS_END = 3;
    const STATUS_FAILED = 4;
    const STATUS_REFUNDED = 5;
    const STATUS_PAY_TIMEOUT = 6;


    const WX_PAY = 1;
    const ALI_PAY = 2;
    const BALANCE = 3;
    const CARD = 4;
    const ADMIN = 5;

    const STATUS_MAP = [
        self::STATUS_UNPAID => '未支付',
        self::STATUS_PAID => '已支付',
        self::STATUS_USING => '使用中',
        self::STATUS_END => '已完成',
        self::STATUS_FAILED => '失败',
        self::STATUS_REFUNDED => '已退款',
        self::STATUS_PAY_TIMEOUT => '支付超时'
    ];


    public function feedback()
    {
        return $this->hasOne(Feedback::class);
    }

    public function device(): BelongsTo
    {
        return $this->belongsTo(Device::class, 'device_id', 'id');
    }

    public function station(): BelongsTo
    {
        return $this->belongsTo(Station::class, 'station_id', 'id');
    }

    public function charge(): BelongsTo
    {
        return $this->belongsTo(ChargeOption::class, 'charge_id', 'id');
    }



    public function distributor(): BelongsTo
    {
        return $this->belongsTo(Distributors::class, 'distributor_id', 'id');
    }

    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class, 'user_id', 'id');
    }

    public function couponRecord(): BelongsTo
    {
        return $this->belongsTo(CouponRecord::class, 'coupon_record_id', 'id');
    }

    public function detail(): HasOne{
        return $this->hasOne(OrderDetail::class, 'number', 'number');
    }

    //
    public function getDurationSeconds()
    {
        return Carbon::now()->timestamp - $this->start_at->timestamp;
    }

    //是否需要通知设备停止
    public function stop($reason, $notifyDevice = false)
    {
        if ($notifyDevice) {
            $packService = new PackService();
            $packService->setCommon($this)->end();
        } else {
            try {
                if ($this->device->is_refund > 0 || $this->is_autoload == 1) { //根据设备状态
                    if (($this->use_fee+$this->charge_service) <= $this->charge->min_price) {
                        $return_fee = $this->fee - $this->charge->min_price;
                    }else{
                        $return_fee = $this->fee - $this->use_fee - $this->charge_service;
                    }
                    if($return_fee <= 0){
                        $return_fee = 0;
                    }
                } else {
                    $return_fee = 0;
                }
                $return_fee = round($return_fee,2);
                if ($this->payment_type == Bill::PAYMENT_TYPE_BALANCE) {
                    $this->user->decrementBalance($this->fee - $return_fee);
                    Bill::record(
                        $this->user,
                        -($this->fee - $return_fee),
                        Bill::TYPE_ORDER_PAY,
                        Bill::PAYMENT_TYPE_BALANCE,
                        $this->id
                    );
                    $this->return_fee+=$return_fee;
                } else {
                    if ($return_fee > 0) {
                        $normal = new Normal();
                        $data['openid'] = $this->user->openid;
                        $data['number'] = $this->number;
                        $data['refund_no'] = 'RF' . $normal->randOrder($this->device_id);
                        $type['pay_type'] = $this->payment_type;
                        if($this->payment_type == Bill::PAYMENT_TYPE_WE_CHAT_PAY){
                            $data['notify_url'] = Common::MAIN_HOST . '/user/order/wx_refund';
                            $save['payment_type'] = 1;
                        }else{
                            $save['payment_type'] = 2;
                        }
                        $data['return_fee'] = $return_fee;
                        $data['fee'] = $this->fee;

                        $save['number'] = $this->number;
                        $save['refund_no'] = $data['refund_no'];
                        $save['type'] = 1;
                        $save['status'] = 0;
                        $save['reject_amt'] = $return_fee * 100;
                        RefundLog::create($save);
                        try{
                            $payModel = PaymentStrategyFactory::createPaymentStrategy($type);
                            $payModel->refund($data);
                        }catch (\Exception $e){
                            Normal::logger($this->number.'发起退款失败'.$e->getMessage().$e->getTraceAsString(),'home');
                        }
//                        $data['type'] = 1;
//                        $data['fee'] = $return_fee;
//                        $bankService = new BankService();
//                        $result = $bankService->refundData($data);
//                        if ($result['return_code'] != 0) {
//                            $return_fee = 0;
//                        }
                    }
                }
                $this->stop_reason = $reason;
                $this->status = self::STATUS_END;
                $this->duration_seconds = $this->getDurationSeconds();
                $this->stop_at = Carbon::now();
                $this->feeStatics($return_fee);
                $this->distributorSettle($return_fee);
                $this->save();
            } catch (\Exception $e) {
                Normal::logger($this->id . '结算失败: ' . $e->getMessage() . '----' . $e->getTraceAsString(), 'order-event');
            }
        }

    }

    /**将数据同步给缓存进行统计
     * @return void
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function feeStatics($return_fee)
    {

    }





    public function fail($reason, $notifyDevice = false)
    {
        $this->status = self::STATUS_FAILED;
        $this->stop_reason = $reason;
        $this->stop_at = Carbon::now();
        $this->save();
        try {
            //有优惠卷就标记为未使用
            $couponRecord = $this->couponRecord;
            $couponRecord && $couponRecord->markAsUnused();
            $this->refund();
            if ($notifyDevice) {
                $packService = new PackService();
                $packService->setCommon($this)->end();
            }
        } catch (\Exception $exception) {
            Normal::logger($this->id . '退款失败: ' . $exception->getMessage(), 'order-event');
        }
    }


    public function balancePay(array $extra = [])
    {
        $config = [
            'code' => 200,
            'need_pay' => false,
            'number' => $this->number
        ];
        if ($this->fee <= 0) {
            $this->paySuccess();
            return $config;
        }
        $user = $this->user;
        switch ($this->payment_type) {
            case Bill::PAYMENT_TYPE_BALANCE:
                if (!$user) {
                    return array('code' => 1001, 'msg' => '用户不存在');
                }
                if ($this->fee > $user->getTotalBalance()) {
                    return array('code' => 1001, 'msg' => '余额不足');
                }
                $this->paySuccess();
                break;
            default:
                //...
        }
        return $config;
    }

    /**支付宝微信支付回调
     * @param array $params
     * @return void
     */
    public function payMent(array $params)
    {
        $this->pay_at = $params['pay_time'];
        $this->out_ord_id = $params['out_ord_id'];
        $this->save();
        $this->paySuccess();
    }

    public function paySuccess()
    {
        //尝试开始充电
        try {
            //尝试开始充电
            $this->status = Order::STATUS_PAID;
            $packService = new PackService();
            if ($this->charge->type == 1) {
                $packService->setCommon($this)->power();
            } else {
                $packService->setCommon($this)->service();
            }
            //有优惠卷就标记为已使用
            $couponRecord = $this->couponRecord;
            $couponRecord && $couponRecord->markAsUsed();
        } catch (\Exception $exception) {
            $message = $exception->getMessage();
            //标记为租用失败
            $this->fail($message);
        }
    }

    public function checkCanRefund()
    {
        //完成的订单和失败的才能退款
        if (!in_array($this->status, [
            self::STATUS_FAILED,
            self::STATUS_END,
            self::STATUS_PAID
        ])) {
            return false;
        }

        //有用户的订单都表示是线上支付的 就可以退
        if (!$this->user) {
            return false;
        }

        return true;
    }



    /**自定义退款
     * @param $params
     * @return void
     */
    public function normalRefundSuccess($params)
    {
        $fee = $params['fee'];
        $deviceModel = Device::where('id', $this->device_id)->first();
        $firstDis = Distributors::where('id', $deviceModel->distributor_id)
            ->first();
        if ($deviceModel->child_distributor_id) {
            $childDis = Distributors::where('id', $deviceModel->child_distributor_id)
                ->first();
            $childDis->balance -= $fee;
            $childDis->save();
            $distributorDevice = DistributorDevice::where('distributor_id', $childDis->id)
                ->where('device_id', $this->device_id)
                ->first();
            if ($distributorDevice) {
                $distributorDevice->profit -= $fee;
                $distributorDevice->save();
            } else {
                $profit['profit'] = -$fee;
                $profit['distributor_id'] = $childDis->id;
                $profit['device_id'] = $this->device_id;
                DistributorDevice::create($profit);
            }
            $bills = Bill::where('target_id', $this->id)
                ->where('account_id', $deviceModel->child_distributor_id)
                ->first();
            if ($bills) {
                $bills->fee -= $fee;
                $bills->balance -= $fee;
                $bills->save();
            }
        } else {
            $firstMoney = $fee;
            $firstDis->balance -= $firstMoney;
            $firstDis->save();
            $distributorDevice = DistributorDevice::where('distributor_id', $firstDis->id)
                ->where('device_id', $this->device_id)
                ->first();
            if ($distributorDevice) {
                $distributorDevice->profit -= $firstMoney;
                $distributorDevice->save();
            } else {
                $profit['profit'] = -$firstMoney;
                $profit['distributor_id'] = $firstDis->id;
                $profit['device_id'] = $this->device_id;
                DistributorDevice::create($profit);
            }
            $bills = Bill::where('target_id', $this->id)
                ->where('account_id', $deviceModel->distributor_id)
                ->first();
            if ($bills) {
                $bills->fee -= $firstMoney;
                $bills->balance -= $firstMoney;
                $bills->save();
            }
        }
    }

    /**自定义退款操作
     * @param $fee
     * @return string|void
     */
    public function normalRefund($fee)
    {
        if ($this->status != self::STATUS_END && $this->status != self::STATUS_REFUNDED) {
            return '';
        }
        switch ($this->payment_type) {
            //支付宝支付退回
            case Bill::PAYMENT_TYPE_ALI_PAY:
                //微信支付退回
            case Bill::PAYMENT_TYPE_WE_CHAT_PAY:
                $refoundParams = array(
                    "payment_id" => $this->payment_id,
                    # 退款订单号
                    "refund_order_no" => 'NR' . rand(99, 999) . $this->number,
                    # 退款金额
                    "refund_amt" => $fee,
                    "notify_url" => Common::MAIN_HOST . '/user/order/refund_normal'
                );
                $adapayService = new AdapayService();
                $adapayService->refundPayment($refoundParams);
                break;
            default:
                $this->return_fee += $fee;
                $this->save();
                $this->user->balance += $fee;
                $this->user->save();
//                $deviceModel = Device::where('id', $this->device_id)->first();
//                $firstDis = Distributors::where('id', $deviceModel->distributor_id)
//                    ->first();
//                if ($deviceModel->child_distributor_id) {
//                    $childDis = Distributors::where('id', $deviceModel->child_distributor_id)
//                        ->first();
//                    $disMoney = number_format($fee * $childDis->rate / 100, 2);
//                    $childDis->balance -= $disMoney;
//                    $childDis->save();
//                    $distributorDevice = DistributorDevice::where('distributor_id', $childDis->id)
//                        ->where('device_id', $this->device_id)
//                        ->first();
//                    if ($distributorDevice) {
//                        $distributorDevice->profit -= $disMoney;
//                        $distributorDevice->save();
//                    } else {
//                        $profit['profit'] = -$disMoney;
//                        $profit['distributor_id'] = $childDis->id;
//                        $profit['device_id'] = $this->device_id;
//                        DistributorDevice::create($profit);
//                    }
//                    $bills = Bill::where('target_id', $this->id)
//                        ->where('account_id', $deviceModel->child_distributor_id)
//                        ->first();
//                    if ($bills) {
//                        $bills->fee -= $disMoney;
//                        $bills->balance -= $disMoney;
//                        $bills->save();
//                    }
//                    if ($firstDis->rate > $childDis->rate) {
//                        $firstRate = $firstDis->rate - $childDis->rate;
//                        if ($firstRate > 0) {
//                            $firstMoney = number_format($fee * $firstRate / 100, 2);
//                            $firstDis->balance -= $firstMoney;
//                            $firstDis->save();
//                            $distributorDevice = DistributorDevice::where('distributor_id', $firstDis->id)
//                                ->where('device_id', $this->device_id)
//                                ->first();
//                            if ($distributorDevice) {
//                                $distributorDevice->profit -= $firstMoney;
//                                $distributorDevice->save();
//                            } else {
//                                $profit['profit'] = -$firstMoney;
//                                $profit['distributor_id'] = $firstDis->id;
//                                $profit['device_id'] = $this->device_id;
//                                DistributorDevice::create($profit);
//                            }
//                            $bills = Bill::where('target_id', $this->id)
//                                ->where('account_id', $deviceModel->distributor_id)
//                                ->first();
//                            if ($bills) {
//                                $bills->fee -= $firstMoney;
//                                $bills->balance -= $firstMoney;
//                                $bills->save();
//                            }
//                        }
//                    }
//                } else {
//                    $firstMoney = number_format($fee * $firstDis->rate / 100, 2);
//                    $firstDis->balance -= $firstMoney;
//                    $firstDis->save();
//                    $distributorDevice = DistributorDevice::where('distributor_id', $firstDis->id)
//                        ->where('device_id', $this->device_id)
//                        ->first();
//                    if ($distributorDevice) {
//                        $distributorDevice->profit -= $firstMoney;
//                        $distributorDevice->save();
//                    } else {
//                        $profit['profit'] = -$firstMoney;
//                        $profit['distributor_id'] = $firstDis->id;
//                        $profit['device_id'] = $this->device_id;
//                        DistributorDevice::create($profit);
//                    }
//                    $bills = Bill::where('target_id', $this->id)
//                        ->where('account_id', $deviceModel->distributor_id)
//                        ->first();
//                    if ($bills) {
//                        $bills->fee -= $firstMoney;
//                        $bills->balance -= $firstMoney;
//                        $bills->save();
//                    }
//                }
                break;
        }
    }


    /**常规退款
     * @return string|void
     */
    public function refund()
    {
        //   Normal::logger('is_do_refund:' .$this->number.'-'.$this->fee.'-'.$this->status, 'notify-event');
        if (!$this->checkCanRefund()) {
            return '';
        }
        $normal = new Normal();
        $data['openid'] = $this->user->openid;
        $data['number'] = $this->number;
        try {
            switch ($this->payment_type) {
                //支付宝支付退回
                case Bill::PAYMENT_TYPE_ALI_PAY:
                    if ($this->fee > 0) {
                        $type['pay_type'] = 'alipay_lite';
                        $data['notify_url'] = Common::MAIN_HOST.'/user/order/ali_refund';
                        $data['return_fee'] = $this->fee;
                        $data['fee'] = $this->fee;
                        $data['refund_no'] ='RF'.$normal->randOrder($this->id);

                        $save['number'] = $this->number;
                        $save['refund_no'] = $data['refund_no'];
                        $save['type'] = 1;
                        $save['status'] = 0;
                        $save['reject_amt'] = $this->fee*100;
                        $save['payment_type'] = 2;
                        RefundLog::create($save);


                        $payModel = PaymentStrategyFactory::createPaymentStrategy($type);
                        $result = $payModel->refund($data);
                        Normal::logger('退款结果打印-save------' .json_encode($result), 'notify-event');
                    }
                //微信支付退回
                case Bill::PAYMENT_TYPE_WE_CHAT_PAY:
                    if ($this->fee > 0) {
                        $type['pay_type'] = 'wx_lite';
                        $data['notify_url'] = Common::MAIN_HOST . '/user/order/wx_refund';
                        $data['return_fee'] = $this->fee;
                        $data['fee'] = $this->fee;
                        $data['refund_no'] = 'RF' . $normal->randOrder($this->id);


                        $save['number'] = $this->number;
                        $save['refund_no'] = $data['refund_no'];
                        $save['type'] = 1;
                        $save['status'] = 0;
                        $save['reject_amt'] = $this->fee * 100;
                        $save['payment_type'] = 1;
                        RefundLog::create($save);

                        $payModel = PaymentStrategyFactory::createPaymentStrategy($type);
                        $result =  $payModel->refund($data);
                        Normal::logger('退款结果打印-save------' .json_encode($result), 'notify-event');
                    }
                    break;
                default:
            }
            if ($this->payment_type == Bill::PAYMENT_TYPE_BALANCE) {
                $this->return_fee = $this->fee;
                $this->refund_at = Carbon::now();
            }
//            else {
//                if (isset($result['return_code']) && $result['return_code'] == 0) {
//                    $this->return_fee = $this->fee;
//                }
//            }
            $this->status = self::STATUS_REFUNDED;
            $this->save();
            //有优惠卷就标记为未使用
            $couponRecord = $this->couponRecord;
            $couponRecord && $couponRecord->markAsUnused();
        } catch (\Exception $e) {
            Normal::logger('退款代码-save-error--------' . $e->getMessage() . $e->getTraceAsString(), 'notify-event');
        }
    }

    /**退款分账流水
     * @param $params
     * @return void
     */
    public function refundSuccess($params)
    {
        $this->return_fee = $params['refund_amt'];
        $this->save();
        if ($params['refund_amt'] < $this->power_fee) {
            $this->distributorSettle();
        }
    }

    /**经销商盈利
     * @return void
     */
    public function distributorSettle($return_fee)
    {
        try {
            $orderMoney = $this->charge_service;
            if ($orderMoney <= 0) {
                return '';
            }
            $deviceModel = Device::where('id', $this->device_id)->first();
            $firstDis = Distributors::where('id', $deviceModel->distributor_id)
                ->first();
            if ($deviceModel->child_distributor_id) {
                $childDis = Distributors::where('id', $deviceModel->child_distributor_id)
                    ->first();
                $disMoney = number_format($orderMoney * $childDis->rate / 100, 2);
                $childDis->balance += $disMoney;
                $childDis->save();
                $distributorDevice = DistributorDevice::where('distributor_id', $childDis->id)
                    ->where('device_id', $this->device_id)
                    ->first();
                if ($distributorDevice) {
                    $distributorDevice->profit += $disMoney;
                    $distributorDevice->save();
                } else {
                    $profit['profit'] = $disMoney;
                    $profit['distributor_id'] = $childDis->id;
                    $profit['device_id'] = $this->device_id;
                    DistributorDevice::create($profit);
                }
                Bill::record(
                    $childDis,
                    $disMoney,
                    Bill::TYPE_ORDER_PAY,
                    $this->payment_type,
                    $this->id
                );
                if ($firstDis->rate > $childDis->rate && $this->is_disabled != 1) {
                    $firstRate = $firstDis->rate - $childDis->rate;
                    if ($firstRate > 0) {
                        $firstMoney = number_format($orderMoney * $firstRate / 100, 2);
                        $firstDis->balance += $firstMoney;
                        $firstDis->save();
                        $distributorDevice = DistributorDevice::where('distributor_id', $firstDis->id)
                            ->where('device_id', $this->device_id)
                            ->first();
                        if ($distributorDevice) {
                            $distributorDevice->profit += $firstMoney;
                            $distributorDevice->save();
                        } else {
                            $profit['profit'] = $firstMoney;
                            $profit['distributor_id'] = $firstDis->id;
                            $profit['device_id'] = $this->device_id;
                            DistributorDevice::create($profit);
                        }
                        Bill::record(
                            $firstDis,
                            $firstMoney,
                            Bill::TYPE_ORDER_PAY,
                            $this->payment_type,
                            $this->id
                        );
                    }
                }
            } else {
                $firstMoney = number_format($orderMoney * $firstDis->rate / 100, 2);
                $firstDis->balance += $firstMoney;
                $firstDis->save();
                $distributorDevice = DistributorDevice::where('distributor_id', $firstDis->id)
                    ->where('device_id', $this->device_id)
                    ->first();
                if ($distributorDevice) {
                    $distributorDevice->profit += $firstMoney;
                    $distributorDevice->save();
                } else {
                    $profit['profit'] = $firstMoney;
                    $profit['distributor_id'] = $firstDis->id;
                    $profit['device_id'] = $this->device_id;
                    DistributorDevice::create($profit);
                }
                Bill::record(
                    $firstDis,
                    $firstMoney,
                    Bill::TYPE_ORDER_PAY,
                    $this->payment_type,
                    $this->id
                );
            }
        } catch (\Exception $e) {
            echo $e->getMessage();
        }
    }


}
